﻿namespace ScrumLite.Data.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Transactions;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Summary description for DeliverableStoreFixture
    /// </summary>
    [TestClass]
    public class DeliverableStoreFixture
    {
        IDeliverableStore store;
        Guid projectId;

        [TestInitialize]
        public void Initialize()
        {
            this.store = new DeliverableStore();
            projectId = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434B5A");
        }

        [TestMethod()]
        public void ShouldReturnZeroDeliverablesForANotExistingProject()
        {
            IList<Deliverable> deliverables = this.store.GetDeliverables(Guid.NewGuid().ToString());

            Assert.AreEqual(0, deliverables.Count);
        }

        [TestMethod()]
        public void ShouldAddDeliverable()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeDeliverableStore();
                RequestStore requestStore = new RequestStore();
                WorkArea workarea = new WorkArea { id = Guid.NewGuid(), fk_project = projectId, name = "WorkArea 1" };
                requestStore.SaveWorkArea(workarea);

                Guid deliverableId = Guid.NewGuid();

                DeliverableWorkArea deliverableWA = new DeliverableWorkArea { id = Guid.NewGuid(), pk_deliverable = deliverableId, pk_workarea = workarea.id };
                System.Data.Linq.EntitySet<DeliverableWorkArea> deliverableWASet = new System.Data.Linq.EntitySet<DeliverableWorkArea>();
                deliverableWASet.Add(deliverableWA);

                Deliverable deliverable = new Deliverable()
                {
                    id = Guid.NewGuid(),
                    pk_project = projectId,
                    moniker = 1,
                    fileName = "drop.zip",
                    uri_repository = "http://some url",
                    releasedOn = DateTime.Now,
                    DeliverableWorkAreas = deliverableWASet
                };

                this.store.Add(deliverable);

                Deliverable actual = this.store.GetDeliverable(deliverable.id);
                WorkArea[] workAreas = store.GetWorkAreas(deliverable.id);

                Assert.AreEqual(deliverable.id, actual.id);
                Assert.AreEqual(deliverable.pk_project, actual.pk_project);
                Assert.AreEqual(deliverable.moniker, actual.moniker);
                Assert.AreEqual(deliverable.releasedOn.Date, actual.releasedOn.Date);
                Assert.AreEqual(deliverable.uri_repository, actual.uri_repository);
                Assert.AreEqual(deliverable.DeliverableWorkAreas.Count, workAreas.Length);
            }
        }

        [TestMethod()]
        public void ShouldUpdateDeliverable()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeDeliverableStore();
                RequestStore requestStore = new RequestStore();
                WorkArea workarea = new WorkArea { id = Guid.NewGuid(), fk_project = projectId, name = "WorkArea 1"};
                requestStore.SaveWorkArea(workarea);
                
                Guid deliverableId = Guid.NewGuid();

                DeliverableWorkArea deliverableWA = new DeliverableWorkArea { id = Guid.NewGuid(), pk_deliverable = deliverableId, pk_workarea = workarea.id };
                System.Data.Linq.EntitySet<DeliverableWorkArea> deliverableWASet = new System.Data.Linq.EntitySet<DeliverableWorkArea>();
                deliverableWASet.Add(deliverableWA);

                int originalMoniker = 1;

                Deliverable deliverable = new Deliverable()
                {
                    id = deliverableId,
                    pk_project = projectId,
                    moniker = originalMoniker,
                    fileName = "drop.zip",
                    uri_repository = "http://some url",
                    releasedOn = DateTime.Now,
                    DeliverableWorkAreas = deliverableWASet
                };

                this.store.Add(deliverable);

                deliverable.fileName = "filename updated";
                deliverable.releasedOn = DateTime.Now.Subtract(TimeSpan.FromDays(1));
                deliverable.uri_repository = "http://some url_updated";
                deliverable.moniker = originalMoniker + 1;

                store.Update(deliverable);

                Deliverable actual = store.GetDeliverable(deliverable.id);
                WorkArea[] workAreas = store.GetWorkAreas(deliverable.id);

                Assert.AreEqual(originalMoniker, actual.moniker);
                Assert.AreEqual(deliverable.fileName, actual.fileName);
                Assert.AreEqual(deliverable.releasedOn.Date, actual.releasedOn.Date);
                Assert.AreEqual(deliverable.uri_repository, actual.uri_repository);
                Assert.AreEqual(deliverable.DeliverableWorkAreas.Count, workAreas.Length);
            }
        }

        [TestMethod()]
        public void ShouldGetDeliverableByMoniker()
        {
            Guid del1 = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434AAA");
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeDeliverableStore();

                Guid actual = this.store.GetDeliverableByMoniker(projectId.ToString(), 1);

                Assert.AreEqual(del1, actual);
            }
        }

        [TestMethod()]
        public void ShouldGetDeliverableByWorkArea()
        {
            Guid wa1Id = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434B5B");
            Guid del1 = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434AAA");
            Guid del2 = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434BBB");
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeDeliverableStore();
                WorkArea wa = new WorkArea() { id = wa1Id, fk_project = projectId, name = "workAreaTest" };

                Deliverable[] actual = this.store.GetDeliverablesByWorkArea(wa);

                Assert.IsNotNull(actual);
                Assert.AreEqual(2, actual.Length);
                Assert.IsTrue(actual[0].id != actual[1].id);
                Assert.IsTrue(actual[0].id == del2 || actual[0].id == del1);
                Assert.IsTrue(actual[1].id == del2 || actual[1].id == del1);
            }
        }

        [TestMethod()]
        public void ShouldCheckDefects()
        {
            Guid del1 = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434AAA");
            Guid del2 = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434BBB");
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeDeliverableStore();

                bool actual = this.store.IsDefect(del1);
                Assert.IsTrue(actual);

                actual = this.store.IsDefect(del2);
                Assert.IsFalse(actual);
            }
        }


        [TestMethod()]
        public void ShouldReturnLastMoniker()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                CreateFakeDeliverableStore();
                int moniker = this.store.RetrieveLastMoniker(projectId.ToString());

                Assert.AreEqual(3, moniker);
            }
        }

        private static void CreateFakeDeliverableStore()
        {
            Guid projectId = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434B5A");
            Guid del1 = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434AAA");
            Guid del2 = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434BBB");
            Guid wa1Id = new Guid("1C4F9968-8D5E-4d8a-9BD8-9A8DF1434B5B");

            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                Project project = new Project() { endsOn = DateTime.Today, id = projectId, name = "FakeProject", security_group = "", startsOn = DateTime.Today, uri_repository = "", user_ownedBy = "" };
                context.Projects.InsertOnSubmit(project);

                WorkArea workArea = new WorkArea() { id = wa1Id, name = "workAreaTest", fk_project = projectId };
                context.WorkAreas.InsertOnSubmit(workArea);
                
                Deliverable deliverable1 = new Deliverable() { fileName = "test1", id = del1, moniker = 1, pk_project = projectId, releasedOn = DateTime.Now, uri_repository = "" };
                Deliverable deliverable2 = new Deliverable() { fileName = "test2", id = del2, moniker = 2, pk_project = projectId, releasedOn = DateTime.Now, uri_repository = "" };
                Deliverable deliverable3 = new Deliverable() { fileName = "test3", id = Guid.NewGuid(), moniker = 3, pk_project = projectId, releasedOn = DateTime.Now, uri_repository = "" };
                context.Deliverables.InsertOnSubmit(deliverable1);
                context.Deliverables.InsertOnSubmit(deliverable2);
                context.Deliverables.InsertOnSubmit(deliverable3);

                DeliverableWorkArea dwa1 = new DeliverableWorkArea() { id = Guid.NewGuid(), pk_deliverable = del1, pk_workarea = wa1Id };
                DeliverableWorkArea dwa2 = new DeliverableWorkArea() { id = Guid.NewGuid(), pk_deliverable = del2, pk_workarea = wa1Id };
                context.DeliverableWorkAreas.InsertOnSubmit(dwa1);
                context.DeliverableWorkAreas.InsertOnSubmit(dwa2);

                Defect defect1 = new Defect() { id = Guid.NewGuid(), createdOn = DateTime.Today, fk_deliverable = del1, moniker = 1, decision = "", triagedOn = null, notes = "", severity = null, title = "", user_createdBy = "tester" };
                context.Defects.InsertOnSubmit(defect1);

                context.SubmitChanges();
            }
        }
    }
}
